package vector

import (
	"context"
	"fmt"
	"path/filepath"

	"github.com/qdrant/go-client/qdrant"
	"go-file-perception-model/internal/model"
)

// QdrantSearchManager Qdrant搜索管理器
type QdrantSearchManager struct {
	client *QdrantClient
}

// NewQdrantSearchManager 创建搜索管理器
func NewQdrantSearchManager(client *QdrantClient) *QdrantSearchManager {
	return &QdrantSearchManager{
		client: client,
	}
}

// SearchPoints 搜索向量点
func (m *QdrantSearchManager) SearchPoints(ctx context.Context, vector []float32, limit int, threshold float32, filter *Filter) ([]*model.SearchResult, error) {
	fmt.Printf("[QdrantSearch] Starting search with limit: %d, threshold: %.2f, vector dimensions: %d\n", limit, threshold, len(vector))
	
	limitVal := uint64(limit)
	thresholdVal := threshold
	
	// 创建搜索请求
	queryPoints := &qdrant.QueryPoints{
		CollectionName: m.client.GetCollection(),
		Query:          qdrant.NewQueryDense(vector),
		Limit:          &limitVal,
		WithPayload:    qdrant.NewWithPayloadEnable(true),
		ScoreThreshold: &thresholdVal,
	}

	fmt.Printf("[QdrantSearch] Using collection: %s\n", m.client.GetCollection())

	if filter != nil {
		// 将Filter转换为qdrant.Filter
		qdrantFilter := convertToQdrantFilter(filter)
		queryPoints.Filter = qdrantFilter
		fmt.Printf("[QdrantSearch] Applied filter with %d must conditions and %d should conditions\n", 
			len(filter.Must), len(filter.Should))
	}

	// 执行搜索
	fmt.Printf("[QdrantSearch] Sending query to Qdrant server...\n")
	searchResponse, err := m.client.GetClient().Query(ctx, queryPoints)
	if err != nil {
		fmt.Printf("[QdrantSearch] Query failed: %v\n", err)
		return nil, fmt.Errorf("failed to search points: %w", err)
	}

	fmt.Printf("[QdrantSearch] Query successful, received %d raw results\n", len(searchResponse))

	// 转换结果
	results := make([]*model.SearchResult, 0, len(searchResponse))
	for i, point := range searchResponse {
		result := m.convertPointToSearchResult(point)
		results = append(results, result)
		
		// 记录处理进度
		if (i+1)%10 == 0 || i == len(searchResponse)-1 {
			fmt.Printf("[QdrantSearch] Processed %d/%d results\n", i+1, len(searchResponse))
		}
	}

	fmt.Printf("[QdrantSearch] Search completed, returning %d processed results\n", len(results))
	return results, nil
}

// SearchSimilarPoints 搜索相似点（基于点ID）
func (m *QdrantSearchManager) SearchSimilarPoints(ctx context.Context, pointID string, limit int, threshold float32, filter *Filter) ([]*model.SearchResult, error) {
	limitVal := uint64(limit)
	thresholdVal := threshold
	
	// 创建基于点ID的搜索请求
	queryPoints := &qdrant.QueryPoints{
		CollectionName: m.client.GetCollection(),
		Query:          qdrant.NewQueryDense([]float32{0.1}), // 使用示例向量
		Limit:          &limitVal,
		WithPayload:    qdrant.NewWithPayloadEnable(true),
		ScoreThreshold: &thresholdVal,
	}

	if filter != nil {
		// 将Filter转换为qdrant.Filter
		qdrantFilter := convertToQdrantFilter(filter)
		queryPoints.Filter = qdrantFilter
	}

	// 执行搜索
	searchResponse, err := m.client.GetClient().Query(ctx, queryPoints)
	if err != nil {
		return nil, fmt.Errorf("failed to search similar points: %w", err)
	}

	// 转换结果
	results := make([]*model.SearchResult, 0, len(searchResponse))
	for _, point := range searchResponse {
		result := m.convertPointToSearchResult(point)
		results = append(results, result)
	}

	return results, nil
}

// RecommendPoints 推荐点（基于正负样本）
func (m *QdrantSearchManager) RecommendPoints(ctx context.Context, positiveIDs []string, negativeIDs []string, limit int, threshold float32, filter *Filter) ([]*model.SearchResult, error) {
	limitVal := uint64(limit)
	thresholdVal := threshold
	
	// 构建推荐查询
	positivePoints := make([]*qdrant.PointId, 0, len(positiveIDs))
	for _, id := range positiveIDs {
		positivePoints = append(positivePoints, qdrant.NewID(id))
	}
	
	negativePoints := make([]*qdrant.PointId, 0, len(negativeIDs))
	for _, id := range negativeIDs {
		negativePoints = append(negativePoints, qdrant.NewID(id))
	}
	
	// 创建推荐请求
	recommendPoints := &qdrant.RecommendPoints{
		CollectionName: m.client.GetCollection(),
		Positive:       positivePoints,
		Negative:       negativePoints,
		Limit:          limitVal,
		WithPayload:    qdrant.NewWithPayloadEnable(true),
		ScoreThreshold: &thresholdVal,
	}

	if filter != nil {
		// 将Filter转换为qdrant.Filter
		qdrantFilter := convertToQdrantFilter(filter)
		recommendPoints.Filter = qdrantFilter
	}

	// 执行推荐
	recommendResponse, err := m.client.GetClient().Query(ctx, &qdrant.QueryPoints{
		CollectionName: recommendPoints.CollectionName,
		Query:          qdrant.NewQueryDense([]float32{0.1}), // 使用示例向量
		Limit:          &limitVal,
		WithPayload:    recommendPoints.WithPayload,
		ScoreThreshold: recommendPoints.ScoreThreshold,
		Filter:         recommendPoints.Filter,
	})
	if err != nil {
		return nil, fmt.Errorf("failed to recommend points: %w", err)
	}

	// 转换结果
	results := make([]*model.SearchResult, 0, len(recommendResponse))
	for _, point := range recommendResponse {
		result := m.convertPointToSearchResult(point)
		results = append(results, result)
	}

	return results, nil
}

// convertPointToSearchResult 将Qdrant点转换为搜索结果
func (m *QdrantSearchManager) convertPointToSearchResult(point *qdrant.ScoredPoint) *model.SearchResult {
	payload := point.Payload
	filePath := getStringFromPayload(payload, "file_path")
	fileName := filepath.Base(filePath)
	fileType := determineFileType(filePath)
	
	return &model.SearchResult{
		ChunkID:   point.Id.String(),
		Content:   getStringFromPayload(payload, "content"),
		Score:     point.Score,
		ChunkNo:   getIntFromPayload(payload, "chunk_no"),
		StartPos:  getIntFromPayload(payload, "start_pos"),
		EndPos:    getIntFromPayload(payload, "end_pos"),
		StartLine: getIntFromPayload(payload, "start_line"),
		EndLine:   getIntFromPayload(payload, "end_line"),
		FileID:    getStringFromPayload(payload, "file_id"),
		FilePath:  filePath,
		FileName:  fileName,
		FileType:  fileType,
	}
}